#! /usr/bin/env python3
# -*- coding: utf-8 -*-

from untils import log, encode_code
from urllib import parse
import socket
from routes import route_dict, error_static


class Request(object):
    def __init__(self, **args):
        self.path = ''
        self.query = {}
        self.method = ''
        self.body = ''
        self.headers = {}
        self.cookie = {}

    def form(self, ):
        body = parse.unquote(self.body)
        args = body.split('&')
        r = {}
        log('request.form-----args:', args)
        for arg in args:
            if '=' in arg:
                k, v = arg.split('=')
                r[k] = v
        return r

    def add_cookie(self, cookie_string):
        """
        set request' cookie
        """
        cookie = {}
        if cookie_string != '':
            for i in cookie_string.split(';'):
                k, v = i.split('=', 1)
                cookie[k.strip()] = v.strip()
            self.cookie = cookie

    def add_headers(self, head_string):
        """
        ['Host: localhost:3000',
        'Connection: keep-alive',
        'Upgrade-Insecure-Requests: 1',
        'DNT: 1', 'Cache-Control: max-age=0']

        format to :
        {
        'Host': 'localhost:3000',
        'Accept-Language': 'zh-CN,en-US;q=0.7,en;q=0.3',
        'Upgrade-Insecure-Requests': '1',
        }
        """
        hs = head_string
        for h in hs:
            k, v = h.split(':', 1)
            self.headers[k.strip()] = v.strip()
        self.cookies = {}
        cookie_string = self.headers.get('Cookie', '')
        self.add_cookie(cookie_string)


request = Request()


def error(request, code=404):

    p = {404: 'templates/404.html'}
    with open(p.get(code), 'r') as rf:
        response = rf
    return response


def parsed_path(path):
    """
    path: /main?user=tom&passwd=123
    return:
      path: /main
      query: {
               'user': 'tom',
               'passwd': '123',
              }
    """
    # path = parse.unquote(path)
    path_split = path.split('?', 1)
    query = {}
    if len(path_split) <= 1:
        # no query , path = path , query = {}
        pass
    else:
        path, query_string = path_split

        for args in query_string.split('&'):
            k, v = args.split('=', 1)
            query[k] = v
    return path, query


def response_for_path(path):
    path, query = parsed_path(path)
    request.path = path
    request.query = query
    p = {}
    p.update(route_dict)
    response = p.get(path, error_static)
    return response(request)


def recive_all(connection):
    r = b''
    recive_len = 1024
    while True:
        log('waiting request ........')
        tmp = connection.recv(recive_len)
        r += tmp
        if tmp == b'' or len(tmp) <= recive_len:
            log('recive all request!', level='debug')
            break
    return r


def handle_recv(recv):
    r = recv
    r_split = r.split()
    method = r_split[0]
    path = r_split[1]
    head_body_sp = r.split('\r\n\r\n')
    body = head_body_sp[1]
    header = head_body_sp[0].split('\r\n')[1:]
    return method, path, body, header


def run(host='', port=3000):
    log('start at {} {}'.format(host, port), level='info')
    with socket.socket() as s:
        # 假如端口被socket使用过，并且利用socket.close()来关闭连接，但
        # 此时端口还没有释放，要经过一个TIME_WAIT的过程之后才能使用。
        # 为了实现端口的马上复用，可以选择setsockopt()函数来达到目的。
        # 如果启用的话, 监听地址最好设置为指定的IP, 例如localhost
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        s.bind((host, port))
        s.listen(5)
        try:
            while True:
                connection, address = s.accept()
                log('connection from {} '.format(address))
                r = recive_all(connection)
                r = r.decode(encode_code)
                log('recive from client : ', r, level='debug')
                if len(r) <= 1:
                    continue
                method, path, body, header = handle_recv(r)
                request.add_headers(header)
                request.body = body
                request.method = method
                response = response_for_path(path)
                connection.sendall(response)
                # log('send response: \n{}\n'.format(response))
                connection.close()
                log('connection {} closed !'.format(address), level='debug')
        except KeyboardInterrupt:
            log('get Ctrl+c ,stop by user', level='error')
            s.close()
        finally:
            s.close()


def get_process_id():
    """Return process ids found by (partial) name or regex.

    >>> get_process_id('kthreadd')
    [2]
    >>> get_process_id('watchdog')
    [10, 11, 16, 21, 26, 31, 36, 41, 46, 51, 56, 61]  # ymmv
    >>> get_process_id('non-existent process')
    []
    """
    import subprocess
    out = subprocess.Popen(
        ["netstat -natp |grep 3000 |grep LISTEN |awk '{print $7}'"],
        stdout=subprocess.PIPE,
        shell=True)
    result = out.communicate()
    log('get process id: ', result)
    pid, error = result
    return str(pid)


def kill_process_by_pid(pid):
    """
    Keyword Arguments:
    pid --
    """
    os.kill(pid)


if __name__ == '__main__':
    config = dict(
        host='127.0.0.1',
        port=3000,
    )
    run(**config)
